package com.library.admin.modules.borrowing.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.library.admin.modules.book.service.BookService;
import com.library.admin.modules.book.vo.BookVO;
import com.library.admin.modules.borrowing.entity.Borrowing;
import com.library.admin.modules.borrowing.vo.BorrowingVO;
import com.library.admin.modules.borrowing.bo.BorrowingPage;
import com.library.admin.modules.borrowing.bo.BorrowingInsert;
import com.library.admin.modules.borrowing.bo.BorrowingUpdate;
import com.library.admin.modules.borrowing.mapper.BorrowingMapper;
import com.library.admin.modules.borrowing.struct.BorrowingStructMapper;
import com.library.admin.modules.borrowing.service.BorrowingService;
import com.library.admin.modules.user.entity.User;
import com.library.admin.modules.user.service.UserService;
import com.library.common.enums.AuditStatusEnum;
import com.library.common.enums.BookBorrowingEnum;
import com.library.common.enums.ClassifyEnum;
import com.library.common.enums.ErrorCodeEnum;
import com.library.common.exception.BaseException;
import com.library.system.modules.examine.bo.ExamineInsert;
import com.library.system.modules.examine.service.ExamineService;
import com.library.system.modules.notice.bo.NoticeInsert;
import com.library.system.modules.notice.service.NoticeService;
import com.library.system.util.EmailUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import com.library.common.util.PageCovertUtil;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * @Author xyh
 * @Desc 借阅记录表(Borrowing)表服务实现类
 * @Date 2023-11-09 13:35:13
 */

@Log4j2
@Service("borrowingService")
public class BorrowingServiceImpl extends ServiceImpl<BorrowingMapper, Borrowing> implements BorrowingService {

    @Resource
    private BorrowingStructMapper borrowingStructMapper;
    @Resource
    @Lazy
    private ExamineService examineService;
    @Resource
    private UserService userService;
    @Resource
    private BookService bookService;
    @Resource
    private EmailUtil emailUtil;
    @Resource
    private NoticeService noticeService;

    /**
     * 逾期每天扣费1元
     */
    private static final BigDecimal OVERDUE_FEE_PER_DAY = BigDecimal.valueOf(1.00);
    /**
     * 存储已发送提醒的借阅记录id
     */
    private static final Set<Integer> sentReminders = new HashSet<>();

    @Override
    public IPage<BorrowingVO> queryByPage(BorrowingPage page) {
        // 查询条件
        LambdaQueryWrapper<Borrowing> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(page.getBookName())) {
            queryWrapper.eq(Borrowing::getBookName, page.getBookName());
        }
        if (StrUtil.isNotEmpty(page.getJobNumber())) {
            queryWrapper.eq(Borrowing::getJobNumber, page.getJobNumber());
        }
        if (StrUtil.isNotEmpty(page.getRealName())) {
            queryWrapper.eq(Borrowing::getRealName, page.getRealName());
        }
        if (page.getBorrowStatus() != null) {
            queryWrapper.eq(Borrowing::getBorrowStatus, page.getBorrowStatus());
        }
        if (page.getUserId() != null) {
            queryWrapper.eq(Borrowing::getUserId, page.getUserId());
        }
        queryWrapper.orderByDesc(Borrowing::getCreateTime);
        // 查询分页数据
        Page<Borrowing> borrowingPage = new Page<Borrowing>(page.getCurrent(), page.getSize());
        IPage<Borrowing> pageData = baseMapper.selectPage(borrowingPage, queryWrapper);

        //转换成vo
        IPage<BorrowingVO> records = PageCovertUtil.pageVoCovert(pageData, BorrowingVO.class);
        if (CollUtil.isNotEmpty(records.getRecords())) {
            records.getRecords().forEach(r -> {
                r.setBorrowStatusName(BookBorrowingEnum.getValue(r.getBorrowStatus()));
            });
        }
        return records;
    }


    @Override
    public BorrowingVO queryById(Integer id) {
        Borrowing borrowing = baseMapper.selectById(id);
        BorrowingVO borrowingVO = borrowingStructMapper.borrowingToBorrowingVO(borrowing);
        borrowingVO.setBorrowStatusName(BookBorrowingEnum.getValue(borrowingVO.getBorrowStatus()));
        return borrowingVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insert(BorrowingInsert borrowingInsert) {
        Borrowing borrowing = borrowingStructMapper.insertToBorrowing(borrowingInsert);
        BookVO bookVO = bookService.queryById(borrowingInsert.getBookId());
        //每次限制借阅2本
        if (borrowing.getQuantityNum() > 2) {
            throw new BaseException(ErrorCodeEnum.BORROWING_NUM.getCode(), "每人最多只能借阅2本书！");
        }
        if (bookVO == null) {
            log.error("借阅的图书不存在或系统出现问题，请联系图书管理员, 图书id为：{}", borrowingInsert.getBookId());
            throw new BaseException("借阅的图书不存在或系统出现问题，请联系图书管理员！");
        }
        borrowing.setIsbn(bookVO.getIsbn());
        //免费借阅15天
        borrowing.setBorrowDate(LocalDateTime.now());
        borrowing.setEndDate(LocalDateTime.now().plusDays(15));
        borrowing.setBookName(bookVO.getName());
        //借阅后，图书数量减掉
        if (bookService.updateBookNum(borrowing.getBookId(), borrowing.getQuantityNum(), true)) {
            save(borrowing);
            log.info("图书扣除数量成功！图书id：{}", borrowing.getBookId());
            return true;
        } else {
            throw new BaseException("该图书已被借阅完，目前不可借!");
        }
    }


    @Override
    public boolean update(BorrowingUpdate borrowingUpdate) {
        Borrowing borrowing = borrowingStructMapper.updateToBorrowing(borrowingUpdate);
        updateById(borrowing);
        return true;
    }

    @Override
    public boolean deleteById(Integer id) {
        return removeById(id);
    }

    @Override
    public void returnBook(Integer id) {
        Borrowing borrowing = getById(id);
        borrowing.setReturnDate(LocalDateTime.now().plusDays(17));
        //判断有没有逾期
        if (borrowing.getBorrowStatus().equals(BookBorrowingEnum.OVERDUE.getCode())) {
            //计算费用
            long days = ChronoUnit.DAYS.between(borrowing.getEndDate(), borrowing.getReturnDate());
            BigDecimal overdueFee = BigDecimal.valueOf(borrowing.getQuantityNum())
                    .multiply(OVERDUE_FEE_PER_DAY.multiply(BigDecimal.valueOf(days)));
            borrowing.setFee(overdueFee);
            borrowing.setBorrowDuration((int) days);
        }
        //提交审核
        returnBookAudit(borrowing);
        log.info("还书提交审核，用户号：{}， 图书名：{}", borrowing.getJobNumber(), borrowing.getBookName());
        borrowing.setBorrowStatus(BookBorrowingEnum.RETURN_AUDIT.getCode());
        updateById(borrowing);
    }

    /**
     * 提交审核
     * @param borrowing
     */
    private void returnBookAudit(Borrowing borrowing) {
        ExamineInsert insert = new ExamineInsert();
        insert.setSubmitUsername(borrowing.getRealName());
        insert.setTitle(borrowing.getBookName());
        insert.setContent("用户编号:" + borrowing.getJobNumber() + "," + "ISBN书号:" + borrowing.getIsbn());
        insert.setClassifyId(borrowing.getId());
        examineService.insertExamine(insert, ClassifyEnum.RETURN_BOOK);
        log.info("图书归还提交审核成功！用户：{}", borrowing.getRealName());
    }

    @Override
    public void updateUserBalance(BigDecimal fee, Integer userId) {
        User user = userService.getById(userId);
        if (user != null) {
            if (user.getBalance() != null) {
                if (user.getBalance().compareTo(fee) >= 0) {
                    BigDecimal subtract = user.getBalance().subtract(fee);
                    user.setBalance(subtract);
                    userService.updateById(user);
                    log.info("图书借阅扣费成功！用户：{}", user.getUsername());
                    return;
                }
            }
            throw new BaseException("账户余额不足，扣费失败！");
        }
    }

    @Override
    public void scheduledNotice() {
        //获取所有图书借阅信息
        List<Borrowing> borrowingList = lambdaQuery()
                .eq(Borrowing::getBorrowStatus, BookBorrowingEnum.BORROWING.getCode())
                .list();
        if (CollUtil.isNotEmpty(borrowingList)) {
            for (Borrowing borrowing : borrowingList) {
                isDueSoon(borrowing);
            }
        }
    }

    private void isDueSoon(Borrowing borrowing) {
        LocalDate currentDate = LocalDate.now();
        LocalDate endDate = borrowing.getEndDate().toLocalDate();
        //先判断是否到期，如果到期更新状态。当天到期的，第二天变为到期
        if (!sentReminders.contains(borrowing.getId()) && currentDate.isAfter(endDate)) {
            //过期
            borrowing.setBorrowStatus(BookBorrowingEnum.OVERDUE.getCode());
            updateById(borrowing);
            //发送通知
            String content = "尊敬的编号为:" + borrowing.getJobNumber() + "的读者，您借阅的图书名为："
                    + "《" + borrowing.getBookName() + "》" + "已经到期，为了不产生必要的费用请及时归还，感谢您的支持！";
            String title = "图书逾期提醒";
            sendMessages(borrowing, content, title);
            sentReminders.add(borrowing.getId());
        } else {
            Period period = Period.between(currentDate, endDate);
            if (period.getDays() == 2) {
                //发送通知
                String content = "尊敬的编号为:" + borrowing.getJobNumber() + "的读者，您借阅的图书名为："
                        + "《" + borrowing.getBookName() + "》" + "还有2天到期，为了不产生必要的费用请注意还书时间，感谢您的支持！";
                String title = "还书提醒";
                sendMessages(borrowing, content, title);
            }
        }
    }

    private void sendMessages(Borrowing borrowing, String content, String title) {
        // 这里选择发送邮件、消息通知
        User user = userService.getById(borrowing.getUserId());
        if (user != null) {
            if (StrUtil.isNotEmpty(user.getEmail())) {
                emailUtil.sendFromEmail(user.getEmail(), content, title);
            }
            NoticeInsert noticeInsert = new NoticeInsert();
            noticeInsert.setUserId(user.getId());
            noticeInsert.setNoticeStatus(AuditStatusEnum.SEND_SUCCESS.getCode());
            noticeInsert.setNoticeType(ClassifyEnum.SYSTEM_NOTICE.getCode());
            noticeInsert.setNoticeContent(content);
            noticeInsert.setNoticeTitle(title);
            noticeInsert.setUserName("图书管理员");
            noticeService.insertOrUpdate(noticeInsert);
        }
    }

}
